﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace LoadTestDbToXml
{
    class DataAccessService : IDisposable
    {
        private readonly LoadTest2010DataContext context;
        private readonly List<LoadTestRun> loadTestRuns;

        public DataAccessService(string connectionString)
        {
            context = new LoadTest2010DataContext(connectionString);
            
            loadTestRuns = context.LoadTestRuns.Where(
                run => run.Outcome == "Completed").OrderByDescending(
                run => run.StartTime).ToList();
        }

        public List<LoadTestRun> LoadTestRuns
        {
            get { return loadTestRuns; }
        }

        internal LoadTestRun GetLastTestRun()
        {
            if (loadTestRuns.Count == 0)
            {
                throw new Exception("Cannot find LoadTestRunId in LoadTestRun table");
            }
            LoadTestRun loadTestRun = loadTestRuns[0];
            return loadTestRun;

        }

        public IEnumerable<TestResult> GetResults(int id)
        {
            List<LoadTestTestResult> results = context.LoadTestTestResults.Where(
                result => result.LoadTestRunId == id).OrderBy(
                result => result.TestCaseName).ToList();

            IQueryable<LoadTestTestCaseSummary> summaries = 
                context.LoadTestTestCaseSummaries.Where(summary => summary.LoadTestRunId == id);
            
            
            List<TestResult> list = new List<TestResult>();
            foreach (var result in results)
            {
                var testCaseName = result.TestCaseName;

                var testCaseSummaries = summaries.Where(
                    summary => summary.TestCaseName == testCaseName).ToList();

                if (testCaseSummaries.Count == 0)
                {
                    throw new Exception(string.Format("Can't find summaries for test case {0}", testCaseName));
                }

                var passedTests = GetCounterValue(testCaseSummaries, "Passed Tests", testCaseName);
                var failedTests = GetCounterValue(testCaseSummaries, "Failed Tests", testCaseName);
                var testsPerSecond = GetCounterValue(testCaseSummaries, "Tests/Sec", testCaseName);

                list.Add(new TestResult(result, passedTests, failedTests, testsPerSecond));
            }

            return list;
        }

        private float GetCounterValue(IEnumerable<LoadTestTestCaseSummary> testCaseSummaries, string counterName, string testcaseName)
        {
            var counterSummary = testCaseSummaries.Where(summary => summary.CounterName == counterName).ToArray();
            if (counterSummary.Length == 0)
            {
                throw new Exception(string.Format("Can't find summary for counter {0} in test case {1}", counterName, testcaseName));
            }

            if (counterSummary.Length > 1)
            {
                throw new Exception(string.Format("Found more than 1 summary for counter {0} in test case {1}", counterName, testcaseName));
                
            }

            var testCaseSummary = counterSummary[0];
            return testCaseSummary.CumulativeValue.HasValue ? testCaseSummary.CumulativeValue.Value : -1;
        }

        public IList<LoadTestMessageSummary> GetErrorMessages(int id)
        {
            List<LoadTestMessageSummary> summaries =
                context.LoadTestMessageSummaries.Where(
                result => 
                    result.LoadTestRunId == id && 
                    result.SubType == "TestError").OrderBy(
                    summary => summary.TestCaseName).ToList();

            return summaries;
        }

        public IEnumerable<LoadTestTransactionResults2> GetTransactions(int id)
        {
            List<LoadTestTransactionResults2> results =
                context.LoadTestTransactionResults2s.Where(
                result => result.LoadTestRunId == id).OrderBy(
                result => result.TransactionName).ToList();
            
            return results;
        }

        public IGrouping<int, LoadTestTransactionResults2>[] GetPrevTransactions(int id)
        {
            // Get all the transactions for prev runs
            var transactionResults = context.LoadTestTransactionResults2s.Where(
                result => result.LoadTestRunId < id).ToList();

            List<IGrouping<int, LoadTestTransactionResults2>> transactionsById = 
                transactionResults.GroupBy(
                result => result.LoadTestRunId).OrderByDescending(
                results => results.Key).ToList();

            return transactionsById.ToArray();
        }

        public IEnumerable<LoadTestComputedCounterSample> GetCounters(int id)
        {
            var counterSamples =
                context.LoadTestComputedCounterSamples.Where(sample => sample.LoadTestRunId == id).ToList();
            return counterSamples;
        }

        public void Dispose()
        {
            context.Dispose();
        }
    }

    public class TestResult
    {
        private readonly LoadTestTestResult result;
        private readonly float passedTests;
        private readonly float failedTests;
        private readonly float testsPerSecond;
        private float precentageFailures;

        public TestResult(LoadTestTestResult result, float passedTests, float failedTests, float testsPerSecond)
        {
            this.result = result;
            this.passedTests = passedTests;
            this.failedTests = failedTests;

            precentageFailures = (failedTests/(passedTests + failedTests))*100;

            this.testsPerSecond = testsPerSecond;
        }

        public string TestCaseName
        {
            get { return result.TestCaseName; }
        }

        public object TestsRun
        {
            get
            {
                return result.TestsRun;
            }
        }

        public double Minimum
        {
            get { return result.Minimum; }
        }

        public double Average
        {
            get { return result.Average; }
        }

        public double Maximum
        {
            get { return result.Maximum; }
        }

        public float PassedTests
        {
            get { return passedTests; }
        }

        public float FailedTests
        {
            get { return failedTests; }
        }

        public float PrecentageFailures
        {
            get { return precentageFailures; }
        }

        public float TestsPerSecond
        {
            get { return testsPerSecond; }
        }
    }
}
